﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.IRepository;
using WebApi.Core.IService;
using WebApi.Core.Model;
using Microsoft.Extensions.Configuration;
using WebApi.Core.Common;
using Microsoft.Extensions.Options;
using WebApi.Core.Model.ResponseModels;
using Azure.Core;
using Microsoft.Extensions.Logging;
using WebApi.Core.Repository;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;


namespace WebApi.Core.Service
{
    public class AuthService : IAuthService
    {
        private readonly IUserRepository _userRepository;
        private readonly IRoleRepository _roleRepository;
        private readonly JwtSettings _jwtSettings;
        private readonly ILogger<AuthService> _logger;
        private readonly IRefreshTokenRepository _refreshTokenRepository;
        public AuthService(IUserRepository userRepository, IRoleRepository roleRepository, IOptions<JwtSettings> jwtOptions,ILogger<AuthService> logger, IRefreshTokenRepository refreshTokenRepository) 
        {
            _userRepository = userRepository;
            _roleRepository = roleRepository;
            _jwtSettings = jwtOptions.Value;
            _logger = logger;
            _refreshTokenRepository = refreshTokenRepository;
        }

        public async Task<LoginResult> LoginAsync(Users user)
        {
            try
            {
                if (string.IsNullOrEmpty(user.UserId))
                    throw new Exception("用户名不能为空");

                if (string.IsNullOrEmpty(user.PasswordHash))
                    throw new Exception("密码不能为空");

                var userinfo = await _userRepository.GetUserAsync(user);
                if (userinfo == null)
                    throw new Exception("用户不存在");

                if (!PasswordHasher.Verify(user.PasswordHash, userinfo.PasswordHash))
                    throw new Exception("密码错误");


                var roles = await _roleRepository.GetRolesByUserIdAsync(user.UserId);

                var jti = Guid.NewGuid().ToString("N");

                //生成token
                var accessToken = JwtHepler.GenerateAccessToken(userinfo, roles, _jwtSettings, jti);
                // 生成刷新token
                var refreshToken = JwtHepler.GenerateRefreshToken();
                var refreshExpiry = DateTime.Now.AddMinutes(_jwtSettings.RefreshTokenExpiry);

                // 存储到数据库
                await _refreshTokenRepository.InsertAsync(new RefreshToken
                {
                    Token = refreshToken,
                    Jti = jti,
                    UserId = userinfo.UserId, 
                    ExpiryTime = refreshExpiry
                });

                return new LoginResult
                {
                    UserId = userinfo.UserId,
                    Username = userinfo.UserName,
                    Roles = roles,
                    AccessToken = accessToken,
                    RefreshToken = refreshToken,
                    AccessTokenExpiry = DateTime.Now.AddMinutes(_jwtSettings.AccessTokenExpiry),
                    RefreshTokenExpiry = refreshExpiry
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "登陆异常");
                throw new Exception("登陆失败:" + ex.Message.ToString());
            }
            
        }

        public async Task<long> RegisterAsync(Users user)
        {
            try
            {
                // 参数校验
                if (string.IsNullOrEmpty(user.UserId))
                    throw new Exception("用户账号不能为空");
                if (string.IsNullOrEmpty(user.UserName))
                    throw new Exception("用户名不能为空");
                if (string.IsNullOrEmpty(user.PasswordHash))
                    throw new Exception("密码不能为空");
                if (user.PasswordHash.Length < 4)
                    throw new Exception("密码至少4位");

                // 检查用户名唯一性
                if (await _userRepository.ExistAsync(x => x.UserName == user.UserName))
                    throw new Exception("用户名已存在");

                var userInfo = new Users
                {
                    UserId = user.UserId,
                    UserName = user.UserName,
                    PasswordHash = PasswordHasher.HashPassword(user.PasswordHash),
                    IsActive = true,
                    CreateTime = DateTime.Now
                };

                return await _userRepository.InsertAsync(userInfo);

            }
            catch (Exception ex)
            { 
                _logger.LogError(ex, "注册用户失败");
                throw new Exception("注册用户失败:" + ex.Message.ToString());
            }
            
        }

        public async Task<LoginResult> RefreshTokenAsync(string accessToken, string refreshToken)
        {
            // 参数校验
            if (string.IsNullOrEmpty(accessToken))
                throw new Exception("缺少AccessToken");
            if (string.IsNullOrEmpty(refreshToken))
                throw new Exception("缺少RefreshToken");

            // 解析过期访问令牌
            var principal = JwtHepler.GetPrincipalFromExpiredToken(accessToken, _jwtSettings);
            var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier);

            // 验证刷新Token
            var storedToken = await _refreshTokenRepository.QueryAsync(x => x.UserId == userId && x.Token == refreshToken);

            if (storedToken == null || storedToken.IsUsed || storedToken.IsRevoked)
            {
                throw new SecurityTokenException("无效的刷新Token");
            }

            // 标记已使用
            storedToken.IsUsed = true;
            await _refreshTokenRepository.UpdateAsync(storedToken, x => x.IsUsed);

            // 生成新Token
            var newJti = Guid.NewGuid().ToString("N"); 
            var user = await _userRepository.QueryAsync(x => x.UserId == userId);
            var roles = await _roleRepository.GetRolesByUserIdAsync(userId); 
            var newAccessToken = JwtHepler.GenerateAccessToken(user, roles ,_jwtSettings, newJti);
            var newRefreshToken = JwtHepler.GenerateRefreshToken();
            var newrefreshExpiry = DateTime.Now.AddMinutes(_jwtSettings.RefreshTokenExpiry);

            await _refreshTokenRepository.InsertAsync(new RefreshToken
            {
                Token = newRefreshToken,
                Jti = newJti,
                UserId = userId,
                ExpiryTime = newrefreshExpiry
            });

            return new LoginResult
            {
                UserId = user.UserId,
                Username = user.UserName,
                Roles = roles,
                AccessToken = accessToken,
                RefreshToken = refreshToken,
                AccessTokenExpiry = DateTime.Now.AddMinutes(_jwtSettings.AccessTokenExpiry),
                RefreshTokenExpiry = newrefreshExpiry
            };


        }

    }
}
